package com.liuyu.common.framework.common.util;


import com.google.common.base.Splitter;
import com.liuyu.common.framework.lang.exception.BusinessException;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author LiuYu
 * @Project:power3-cloud
 * @Title:
 * @ClassName:GenerateUtils
 * @Description:
 * @date 2020/2/29 17:39
 * @Copyright:liuyu
 * @version:V1.0
 */
public class GenerateUtils {
    public static final DateTimeFormatter DATE_YEAR_TWO = DateTimeFormatter.ofPattern("yy");
    public static final DateTimeFormatter DATE_YEAR_FOUR = DateTimeFormatter.ofPattern("yyyy");
    public static final DateTimeFormatter DATE_YEAR_MONTH = DateTimeFormatter.ofPattern("yyyyMM");
    public static final DateTimeFormatter DATE_YEAR_DAY = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final Pattern COMPILE = Pattern.compile("\\{(.+?)\\}");
    private static final String YY = "{yy}";
    private static final String YYYY = "{yyyy}";
    private static final String YYYYMM = "{yyyyMM}";
    private static final String YYYYMMDD = "{yyyyMMdd}";

    /**
     * @param arguments
     * @return
     */
    public static String generateKey(Object... arguments) {
        StringBuilder sb = new StringBuilder(arguments[0] + ":" + arguments[1] + ":");
        //第一個作爲namespace
        for (int i = 2; i < arguments.length - 1; i++) {
            if (arguments[i] != null) {
                sb.append(arguments[i]).append(".");
            }
        }
        if (arguments[(arguments.length - 1)] != null) {
            sb.append(arguments[(arguments.length - 1)]);
        }
        return sb.toString();
    }


    /**
     * 根据规则生成代码
     *
     * @param rule
     * @param serialNo
     * @return java.lang.String
     * @throws
     * @author liuyu
     * @date 2022/6/16 10:26
     */
    public static String createCode(String rule, Integer serialNo) {
        StringBuffer comCode = new StringBuffer();
        LocalDate now = LocalDate.now();
        if (rule.contains(YY)) {
            String date = now.format(DATE_YEAR_TWO);
            rule = rule.replace(YY, date);
        } else if (rule.contains(YYYY)) {
            String date = now.format(DATE_YEAR_FOUR);
            rule = rule.replace(YYYY, date);
        } else if (rule.contains(YYYYMM)) {
            String date = now.format(DATE_YEAR_MONTH);
            rule = rule.replace(YYYYMM, date);
        } else if (rule.contains(YYYYMMDD)) {
            String date = now.format(DATE_YEAR_DAY);
            rule = rule.replace(YYYYMMDD, date);
        }
        Matcher m = COMPILE.matcher(rule);
        Integer length = 0;
        String lengthPatten = "";
        while (m.find()) {
            if (m.group().contains("l:")) {
                length = Integer.valueOf(m.group().substring(3, m.group().length() - 1));
                lengthPatten = m.group();
                break;
            }
        }
        rule = rule.replace(lengthPatten, "");


        String rPatten = "";
        String random = "";
        while (m.find()) {
            if (m.group().contains("lr:")) {
                Integer rLength = Integer.valueOf(m.group().substring(4, m.group().length() - 1));
                rPatten = m.group();
                random = IdUtils.creatRandomNum(rLength);
                break;
            }
        }
        rule = rule.replace(rPatten, "");
        int size = length - rule.length();
        if (size <= 0) {
            size = 20;
        }
        int serialNoLength = String.valueOf(serialNo).length();
        int coverLength = size - serialNoLength;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < coverLength; i++) {
            sb.append("0");
        }
        sb.append(serialNo);
        comCode.append(rule);
        comCode.append(sb.toString());
        comCode.append(random);
        return comCode.toString();
    }

    /**
     * 从字符串中获取变量清单
     *
     * @param source
     * @return java.util.List<java.lang.String>
     * @throws
     * @author liuyu
     * @date 2022/6/25 17:20
     */
    public static List<String> getParamListFromString(String source) {
        Matcher m = COMPILE.matcher(source);
        List<String> list = new ArrayList<>();
        while (m.find()) {
            list.add(m.group().substring(1, m.group().length() - 1));
        }
        return list;
    }

    /**
     * 将map中的变量，通过source进行填充
     *
     * @param source
     * @param data
     * @return void
     * @throws
     * @author liuyu
     * @date 2022/6/25 18:07
     */
    public static void invokeFixedValue(Object source, Map<String, String> data) {
        Method[] methods = source.getClass().getDeclaredMethods();
        for (Map.Entry<String, String> stringStringEntry : data.entrySet()) {
            List<String> params = GenerateUtils.getParamListFromString(stringStringEntry.getValue());
            String mapValue = stringStringEntry.getValue();
            for (String param : params) {
                List<String> format = Splitter.on("|").trimResults().omitEmptyStrings().splitToList(param);
                String methodName = format.get(0);
                Object value = null;
                boolean constains = false;
                for (Method method : methods) {
                    if (method.getName().equals(methodName)) {
                        try {
                            value = method.invoke(source);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        } catch (InvocationTargetException e) {
                            throw new RuntimeException(e);
                        }
                        constains = true;
                        break;
                    }
                }
                if (!constains) {
                    throw new BusinessException("{}方法名不存在", methodName);
                }
                if (format.size() > 1) {
                    List<String> formats = Splitter.on(":").trimResults().omitEmptyStrings().splitToList(format.get(1));
                    switch (formats.get(0)) {
                        case "lenFirst":
                            Integer length = Integer.parseInt(formats.get(1));
                            if (value != null) {
                                value = value.toString().substring(0, length);
                            }
                            break;
                        case "lenLast":
                            length = Integer.parseInt(formats.get(1));
                            if (value != null) {
                                Integer strLen = value.toString().length();
                                value = value.toString().substring(strLen - 1 - length, strLen - 1);
                            }
                            break;
                        case "localDateTime":
                            if (value != null) {
                                value = ((LocalDateTime) value).format(DateTimeFormatter.ofPattern(formats.get(1)));
                            }
                            break;
                        default:
                            break;

                    }
                }
                mapValue = mapValue.replace("{" + param + "}", value.toString());
            }
            data.put(stringStringEntry.getKey(), mapValue);
        }
    }

}
